package com.tsingtree.gen.modular.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tsingtree.base.db.util.DbUtil;
import com.tsingtree.base.pojo.page.LayuiPageFactory;
import com.tsingtree.base.pojo.page.LayuiPageInfo;
import com.tsingtree.gen.core.enums.GenDownloadEnum;
import com.tsingtree.gen.core.enums.GenSessionKeyFlags;
import com.tsingtree.gen.core.generator.base.model.ContextParam;
import com.tsingtree.gen.core.generator.ts.Executor;
import com.tsingtree.gen.core.generator.ts.mybatisplus.param.MpParams;
import com.tsingtree.gen.core.util.ConcatUtil;
import com.tsingtree.gen.core.util.FieldsConfigHolder;
import com.tsingtree.gen.modular.model.FieldConfig;
import com.tsingtree.gen.modular.model.GenSessionFieldConfigs;
import com.tsingtree.gen.modular.model.params.ExecuteParam;
import com.tsingtree.gen.modular.model.params.SaveFieldConfigParam;
import com.tsingtree.gen.modular.service.GenerateService;
import com.tsingtree.roses.core.config.properties.DruidProperties;
import com.tsingtree.roses.core.reqres.response.ResponseData;
import com.tsingtree.roses.core.reqres.response.SuccessResponseData;
import com.tsingtree.sys.modular.system.service.IRedisUtilService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 * 代码生成控制器
 *
 * @author jagger
 */
@Controller
@Slf4j
public class GeneratorController {

    @Autowired
    DruidProperties druidProperties;
    @Autowired
    private GenerateService tableService;
    @Autowired
    private IRedisUtilService redisUtilService;

    public static String CONDITION_FIELDS = "CONDITION_FIELDS";


    @RequestMapping("/tableList")
    @ResponseBody
    public Object tableList(HttpServletRequest request) {
        //清空session中的字段条件信息
        HttpSession session = request.getSession();
        session.removeAttribute(CONDITION_FIELDS);

        try {
            List<Map<String, Object>> maps = DbUtil.selectTables(druidProperties);
            Page<Map<String, Object>> objectPage = new Page<>();
            objectPage.setRecords(maps);
            return LayuiPageFactory.createPageInfo(objectPage);
        } catch (Exception e) {
            Page<Map<String, Object>> objectPage = new Page<>();
            return LayuiPageFactory.createPageInfo(objectPage);
        }
    }


    /**
     * 代码生成主页
     *
     * @author jagger
     */
    @RequestMapping("/gen")
    public String index(Model model) {
        //清空session的缓存
        redisUtilService.delete(GenSessionKeyFlags.TABLE_FIELD_SETTING.name());

        return "/modular/gen/gen.html";
    }

    /**
     * 跳转到字段列表页面
     *
     * @author jagger
     */
    @RequestMapping("/tableFields")
    public String tableFields(Long dbId,
                              @RequestParam("tableName") String tableName,
                              Model model) {

        model.addAttribute("tableName", tableName);
        model.addAttribute("dbId", dbId);

        return "/modular/gen/tableFields.html";
    }

    /**
     * 获取表的字段列表
     *
     * @author jagger
     */
    @RequestMapping("/getTableFieldConfigs")
    @ResponseBody
    public LayuiPageInfo getTableFieldConfigs(@RequestParam("tableName") String tableName) {

        //获取这个表的所有字段以及其他信息
        List<FieldConfig> tableFields = tableService.getTableFieldsConfig(tableName);

        LayuiPageInfo layuiPageInfo = new LayuiPageInfo();
        layuiPageInfo.setData(tableFields);
        layuiPageInfo.setCount(tableFields.size());

        return layuiPageInfo;
    }

    /**
     * 设置条件字段
     *
     * @author jagger
     */
    @RequestMapping("/saveFieldsConfig")
    @ResponseBody
    public ResponseData saveFieldsConfig(@RequestBody @Valid SaveFieldConfigParam saveFieldConfigParam) {
        tableService.setTableFieldsConfig(saveFieldConfigParam);
        return new SuccessResponseData();
    }

    /**
     * 执行代码生成
     *
     * @return
     * @author jagger
     */
    @RequestMapping(value = "/execute", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity execute(ExecuteParam executeParam) {

        //获取字符串拼接数组
        String[] tableArray = ConcatUtil.getArray(executeParam.getTables());

        //获取跳转类型的数组
        String[] jumpTypeArray = ConcatUtil.getArray(executeParam.getJumpTypeStr());

        Set<String> jumpTypeSet = CollUtil.newHashSet(jumpTypeArray);
        Map<String, Boolean> jumpTypeMap = new HashMap<>(8);
        for (String tableName : tableArray) {
            jumpTypeMap.put(tableName, jumpTypeSet.contains(tableName));
        }
        ContextParam contextParam = new ContextParam();
        contextParam.setAuthor(executeParam.getAuthor());
        contextParam.setProPackage(executeParam.getProPackage());
        contextParam.setJdbcDriver(druidProperties.getDriverClassName());
        contextParam.setJdbcUserName(druidProperties.getUsername());
        contextParam.setJdbcPassword(druidProperties.getPassword());
        contextParam.setJdbcUrl(druidProperties.getUrl());
        contextParam.setJumpTypeMap(jumpTypeMap);

        String outputPath = "";

        outputPath = new File("").getAbsolutePath() + File.separator + "tsing-main" + File.separator + "src" + File.separator + "main";
        contextParam.setGenDownloadEnum(GenDownloadEnum.PROJECT_PATH);

        contextParam.setOutputPath(outputPath);

        MpParams mpContextParam = new MpParams();
        mpContextParam.setGeneratorInterface(true);
        mpContextParam.setIncludeTables(tableArray);

        if (StrUtil.isNotEmpty(executeParam.getRemovePrefix())) {
            mpContextParam.setRemoveTablePrefix(new String[]{(executeParam.getRemovePrefix())});
        }

        try {
            //将session中的字段配置数据传递到threadlocal中
            String res = redisUtilService.get(GenSessionKeyFlags.TABLE_FIELD_SETTING.name());
            GenSessionFieldConfigs sessionFieldConfigs = JSON.parseObject(res, GenSessionFieldConfigs.class);
            FieldsConfigHolder.put(sessionFieldConfigs);

            Executor.executor(contextParam, mpContextParam);
        } finally {
            FieldsConfigHolder.remove();
        }

        return null;
    }


    /**
     * 返回前台文件流
     *
     * @param fileName    文件名
     * @param inputStream 输入流
     * @return
     * @author 0x0001
     */
    private ResponseEntity<InputStreamResource> renderFile(String fileName, InputStream inputStream) {
        InputStreamResource resource = new InputStreamResource(inputStream);
        String dfileName = null;
        try {
            dfileName = new String(fileName.getBytes("gb2312"), "iso8859-1");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", dfileName);
        return new ResponseEntity<>(resource, headers, HttpStatus.CREATED);
    }

    /**
     * 返回前台文件流
     *
     * @author jagger
     */
    private ResponseEntity<InputStreamResource> renderFile(String fileName, String filePath) {
        try {
            final FileInputStream inputStream = new FileInputStream(filePath);
            return renderFile(fileName, inputStream);
        } catch (FileNotFoundException e) {
            throw new RuntimeException("文件读取错误");
        }
    }

    /**
     * 返回前台文件流
     *
     * @author jagger
     */
    private ResponseEntity<InputStreamResource> renderFile(String fileName, byte[] fileBytes) {
        return renderFile(fileName, new ByteArrayInputStream(fileBytes));
    }


}
